// Copyright (c) 2011 Vratislav Cermak (vratacermak@gmail.com)
//  
// This file is part of SrtSync Project. See http://code.google.com/p/srtsync/ for more information.
//  
// SrtSync is an open source project. Using of SrtSync is free of charge.
// It is distributed under GNU General Public License version 3 (GPLv3).
// GPLv3 can be found at http://www.gnu.org/licenses/gpl.html.
//  
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the license for more details.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SrtSync.Core.Framework;
using SrtSync.Core.Notifications;

namespace SrtSync.Core.Controllers
{
    public class EditorController : IEditorController
    {
        private readonly IDialogs _dialogs;
        private readonly IEditor _editor;
        private readonly IEditorView _editorView;

        public EditorController(IEditor editor, IDialogs dialogs, IEditorView editorView)
        {
            _dialogs = dialogs;
            _editor = editor;
            _editorView = editorView;
            
            _editorView.Register(this);
        }

        public void Process(EditorViewNotification data)
        {
            data.Type.CheckValue();
            string path;

            switch (data.Type)
            {
                case EditorViewNotificationTypes.Open:
                    if (SaveModifiedFile() && _dialogs.OpenFile(out path))
                    {
                        try
                        {
                            _editor.Load(path);
                        }
                        catch (Exception e)
                        {
                            _dialogs.ShowError(String.Format("Could not load file '{0}'.", path), e);
                        }
                    }
                    break;
                case EditorViewNotificationTypes.Load:
                    if (SaveModifiedFile())
                    {
                        try
                        {
                            _editor.Load(data.Path);
                        }
                        catch (Exception e)
                        {
                            _dialogs.ShowError(String.Format("Could not load file '{0}'.", data.Path), e);
                        }   
                    }                    
                    break;
                case EditorViewNotificationTypes.Save:
                    try
                    {
                        _editor.Save();
                    }
                    catch (Exception e)
                    {
                        _dialogs.ShowError(String.Format("Could not save file '{0}'.", _editor.Path), e);
                    }
                    break;
                case EditorViewNotificationTypes.SaveAs:
                    if (_dialogs.SaveFile(out path))
                    {
                        try
                        {
                            _editor.SaveAs(path);
                        }
                        catch (Exception e)
                        {
                            _dialogs.ShowError(String.Format("Could not save file '{0}'.", path), e);
                        }
                    }
                    break;
                case EditorViewNotificationTypes.SaveCopy:
                    if (_dialogs.SaveFile(out path))
                    {
                        try
                        {
                            _editor.SaveCopy(path);
                        }
                        catch (Exception e)
                        {
                            _dialogs.ShowError(String.Format("Could not save file '{0}'.", path), e);
                        }
                    }
                    break;
                case EditorViewNotificationTypes.Close:
                    if (SaveModifiedFile())
                    {
                        _editor.Close();
                    }
                    break;
                case EditorViewNotificationTypes.Delete:
                    _editor.Delete(_editorView.Selection);
                    break;
                case EditorViewNotificationTypes.Merge:
                    _editor.Merge(_editorView.Selection);
                    break;
                case EditorViewNotificationTypes.Encoding:
                    _editor.Encoding = data.Encoding;
                    if (!_editor.Empty && _dialogs.ShowQuestion("Do you want to reload editor content?"))
                    {
                        Reload();
                    }
                    break;
                case EditorViewNotificationTypes.Edit:
                    string text = CreateText(_editorView.Selection);
                    if (_dialogs.EditText(ref text))
                    {
                        _editor.Replace(_editorView.Selection, CreateEntries(text));
                    }
                    break;
                case EditorViewNotificationTypes.Reload:
                    Reload();
                    break;                
            }
        }

        private void Reload()
        {
            if (SaveModifiedFile())
            {
                try
                {
                    _editor.Reload();
                }
                catch (Exception e)
                {
                    _dialogs.ShowError(String.Format("Could not reload file '{0}'.", _editor.Path), e);
                }
            }
        }

        private bool SaveModifiedFile()
        {
            if (_editor.Modified && _dialogs.ShowQuestion("File has been changed. Do you want to save changes?"))
            {
                try
                {
                    _editor.Save();
                }
                catch (Exception e)
                {
                    _dialogs.ShowError(String.Format("Could not save file '{0}'.", _editor.Path), e);

                    return false;
                }
            }

            return true;
        }

        private static string CreateText(IEnumerable<Entry> entries)
        {
            StringBuilder result = new StringBuilder();
            foreach (Entry entry in entries)
            {
                foreach (string line in entry.Texts)
                {
                    result.AppendLine(line);
                }
                result.AppendLine();
            }
            return result.ToString().Trim();
        }

        private static IEnumerable<Entry> CreateEntries(string text)
        {
            List<List<string>> parsedText = new List<List<string>>();
            List<string> current = new List<string>();
            using (TextReader reader = new StringReader(text.Trim()))
            {
                while (true)
                {
                    string line = reader.ReadLine();
                    if (String.IsNullOrEmpty(line))
                    {
                        if (current.Count > 0)
                        {
                            parsedText.Add(current);
                        }
                        if (line == null)
                        {
                            break;
                        }
                        if (current.Count > 0)
                        {
                            current = new List<string>();
                        }
                    }
                    else
                    {
                        current.Add(line);
                    }
                }
            }
            return parsedText.Select(texts => new Entry { Texts = texts.ToArray() }).ToList();
        }
    }
}